<?php
/**
 * Created by PhpStorm.
 * User: yuyj
 * Date: 16-12-12
 * Time: 上午9:52
 */

namespace common\services\outstock;

use common\entities\ContractEntity;
use common\entities\outstock\MyscrmOutStockAttachmentEntity;
use common\entities\outstock\MyscrmOutStockOrderEntity;
use common\entities\outstock\MyscrmOutStockProductEntity;
use common\models\common\ApplicationInfoMappingModel;
use common\repositories\myhtsq\ErpBusinessUnitRepository;
use common\repositories\outstock\OutStockAttachmentRepository;
use common\repositories\outstock\OutStockOrderRepository;
use common\repositories\outstock\OutStockProductRepository;
use common\services\BaseService;
use common\services\common\MyscrmApplicationInfoService;
use common\services\common\MyscrmApplicationService;
use common\services\common\MyscrmAuthorizeService;
use common\services\common\MyscrmContractApplicationService;
use common\services\common\MyscrmContractManageService;
use common\services\common\MyscrmContractProjectService;
use common\services\common\MyscrmContractService;
use common\services\myhtsq\ContractService;
use common\support\StringHelper;
use Yii;
use yii\base\Exception;
use yii\helpers\ArrayHelper;

class OutStockOrderService extends BaseService
{
    private $orderRepository;
    private $productRepository;
    private $attachmentRepository;

    public function __construct(OutStockOrderRepository $orderRepository,
                                OutStockProductRepository $productRepository,
                                OutStockAttachmentRepository $attachmentRepository,
                                $config = [])
    {
        $this->orderRepository = $orderRepository;
        $this->productRepository = $productRepository;
        $this->attachmentRepository = $attachmentRepository;

        return parent::__construct($config);
    }

    public function view($id)
    {
        $order = $this->orderRepository->getOrderById($id);
        $contract_code = $order->contract_code;
        $areaId = $this->_getContractManageAreaIdByContractCode($contract_code);
        $areaName = $this->_getAreaNameByAreaId($areaId);
        $order = ArrayHelper::toArray($order);
        $order['areaId'] = $areaId;
        $order['areaName'] = $areaName;
        $products = $this->productRepository->getProductsByOrderId($id);
        $attachments = $this->attachmentRepository->getAttachmentsByOrderId($id);

        return [
            'order'       => $order,
            'products'    => $products,
            'attachments' => $attachments,
        ];
    }

    /**
     * @param $areaId
     * @return string
     * @throws \yii\base\InvalidConfigException
     */
    private function _getAreaNameByAreaId($areaId)
    {
        $areaName = '';
        if (!empty($areaId)) {
            /** @var ErpBusinessUnitRepository $erpBusinessUnitRepository */
            $erpBusinessUnitRepository = Yii::createObject(ErpBusinessUnitRepository::className());
            $areaName = $erpBusinessUnitRepository->getBunameByBuguid($areaId);
        }

        return $areaName;
    }

    /**
     * @param $contract_code
     * @return mixed|string
     * @throws \yii\base\InvalidConfigException
     */
    private function _getContractManageAreaIdByContractCode($contract_code)
    {
        $areaId = '';
        if (!empty($contract_code)) {
            /** @var MyscrmContractManageService $myscrmContractManageService */
            $myscrmContractManageService = Yii::createObject(MyscrmContractManageService::className());
            $contractManage = $myscrmContractManageService->getContractManageByCode($contract_code);
            $areaId = $contractManage->area_id;
        }

        return $areaId;
    }

    public function save(MyscrmOutStockOrderEntity $order, array $products, array $attachments)
    {
        $transaction = ContractEntity::getDb()->beginTransaction();
        try {
            if ($this->saveOrder($order, $attachments) === false) {
                $transaction->rollBack();

                return false;
            };

            if ($this->saveProduct($order, $products) == false) {
                $transaction->rollBack();

                return false;
            }


            if ($this->saveAttachment($order, $attachments) === false) {
                $transaction->rollBack();

                return false;
            }

            $transaction->commit();

        } catch (Exception $e) {
            $transaction->rollBack();

            return self::setAndReturn($e->getCode(), $e->getMessage());
        }

        return $order->id;
    }

    private function checkOrderOwner(MyscrmOutStockOrderEntity $order, $user)
    {
        if (in_array($user, [$order->request_user_id, $order->response_user_id])) {
            return true;
        } else {
            return self::setAndReturn(__LINE__, '当前用户不能编辑此单据。');
        }
    }

    public function getOrderById($id)
    {
        return $this->orderRepository->getOrderById($id);
    }

    public function delete($id)
    {
        if (empty($id)) {
            return self::setAndReturn(__LINE__, '单据id不得为空');
        }

        return $this->orderRepository->delete($id);
    }

    public function getList($pageSize = 1, $pageNo = 10)
    {
        return $this->orderRepository->getList($pageSize, $pageNo);
    }

    /**
     * 保存单据
     * @param MyscrmOutStockOrderEntity $order
     * @param                           $attachments
     * @return bool|string
     */
    private function saveOrder(MyscrmOutStockOrderEntity $order, array $attachments)
    {
        if ($order->id) {
            $oldOrder = $this->getOrderById($order->id);

            if (empty($oldOrder)) {
                return self::setAndReturn(__LINE__, sprintf('当前单据不存在(%s)', $order->id));
            }

            if ($oldOrder->flow_status != OutStockFlowService::STATUS_WFQ) {
                return self::setAndReturn(__LINE__, '只有未发起的单据才允许修改');
            }

            if ($this->checkOrderOwner($oldOrder, $order->request_user_id) === false) {
                return false;
            }

            //不允许修改的字段
            $order->order_code = $oldOrder->order_code;
            $order->order_status = $oldOrder->order_status;
            $order->flow_status = $oldOrder->flow_status;
            $order->flow_step_id = $oldOrder->flow_step_id;
            $order->created_on = $oldOrder->created_on;

            $oldOrder->setAttributes($order->getAttributes());

            $order = $oldOrder;
        } else {
            // 生成单据编号
            $order->order_code = $this->buildOrderCode();
            $order->order_status = 1;
            $order->flow_status = OutStockFlowService::STATUS_WFQ;
            $order->id = StringHelper::uuid();
        }

        $order->modified_on = date('Y-m-d H:i:s');

        if ($this->validateOrder($order, $attachments) === false) {
            return false;
        }

        return $this->orderRepository->save($order);
    }

    /**
     * 生成单据编号
     * @return string
     */
    private function buildOrderCode()
    {
        $format = '%03d';
        $prefix = date('Ymd');
        $order = $this->orderRepository->getTodayLatestOrder();
        if (empty($order)) {
            return $prefix . sprintf($format, 1);
        } else {
            return $prefix . sprintf($format, substr($order->order_code, strlen($prefix)) + 1);
        }
    }

    /**
     * 验证单据数据
     * @param MyscrmOutStockOrderEntity $order
     * @param array $attachments
     * @return bool
     */
    private function validateOrder(MyscrmOutStockOrderEntity $order, array $attachments)
    {
        //直属
        if ($order->business_pattern == 1 && $order->contract_status == 1 && (!$order->contract_id || !$order->contract_code)) {
            return self::setAndReturn(__LINE__, '直属模式下，请指定合同');
        }

        //联营
        if ($order->business_pattern == 2 && ($order->contract_status == 1 || $order->money_status == 1) && empty($attachments)) {
            return self::setAndReturn(__LINE__, '联营模式下，请上传附件');
        }

        //是否新租户
        if ($order->is_new_org == 0 && (empty($order->org_id) || empty($order->org_code))) {
            return self::setAndReturn(__LINE__, '已有租户，请提供org_id org_code');
        }

        if ($order->is_new_org == 1 && (!empty($order->org_id) || !empty($order->org_code))) {
            return self::setAndReturn(__LINE__, '新租户，请不要提供org_id org_code');
        }

        return true;
    }

    /**
     * 保存产品
     * @param MyscrmOutStockOrderEntity $order
     * @param array $products
     * @return bool
     */
    private function saveProduct(MyscrmOutStockOrderEntity $order, array $products)
    {
        if ($this->validateProduct($order, $products) === false) {
            return false;
        }

        $this->productRepository->deleteByOrderId($order->id);

        return $this->productRepository->batchSave($order->id, $products);
    }

    /**
     * 验证出库的数据是否正确
     * @param MyscrmOutStockOrderEntity $order
     * @param array $products
     * @return bool
     */
    private function validateProduct(MyscrmOutStockOrderEntity $order, array $products)
    {
        if (empty($products)) {
            return self::setAndReturn(__LINE__, '开通产品不能为空。');
        }

        //验证续签绑定的项目与申请的授权数是否一致
        $totalApplyNum = 0;
        foreach ($products as $product) {
            /** @var MyscrmOutStockProductEntity $product */
            if ($product->contract_type == 3 && $product->apply_num != count($product->bind_project)) {
                return self::setAndReturn(__LINE__, '开通产品数与绑定项目数量不符');
            }

            $product->id = StringHelper::uuid();

            $totalApplyNum += $product->apply_num;
        }

        if ($totalApplyNum < 1) {
            return self::setAndReturn(__LINE__, '本次申请开通产品总数不得小于1');
        }

        //验证剩余的授权数量
        if (
            $order->contract_id &&
            $data = $this->getContractApplicationByContractId($order->org_code, $order->contract_id, $order->id)
        ) {
            $data = ArrayHelper::index($data, 'contract_application_id');

            foreach ($products as $product) {

                if (!array_key_exists($product['contract_application_id'], $data)) {
                    return self::setAndReturn(__LINE__, sprintf('该合同没有购买%s', $product['application_name']));
                }

                $total = $data[$product['contract_application_id']]['authorization_numeric'];
                $used = $data[$product['contract_application_id']]['used_authorization_numeric'];
                if ($product['apply_num'] > $total - $used) {
                    return self::setAndReturn(
                        __LINE__,
                        sprintf('当前申请出库%s[%d]，已超出剩余授权数量。', $product['application_name'], $product['apply_num'])
                    );
                }
            }
        }

        return true;
    }

    private function getTotalAuthorizationNumericContractId()
    {

    }

    private function validateAttachment(array $attachments)
    {
        foreach ($attachments as $attachment) {
            /** @var MyscrmOutStockAttachmentEntity $attachment */
            $attachment->id = StringHelper::uuid();
        }

        return true;
    }

    /**
     * 保存附件
     * @param MyscrmOutStockOrderEntity $order
     * @param array $attachments
     * @return bool
     */
    private function saveAttachment(MyscrmOutStockOrderEntity $order, array $attachments)
    {
        if ($this->validateAttachment($attachments) === false) {
            return false;
        }

        $this->attachmentRepository->deleteByOrderId($order->id);

        return $this->attachmentRepository->batchSave($order->id, $attachments);
    }

    /**
     * 获取合同下商务应用的购买信息
     * @param $orgCode
     * @param $contractId
     * @param null $excludeOrderId 排除某个单据下的购买信息
     * @return mixed
     */
    public function getContractApplicationByContractId($orgCode, $contractId, $excludeOrderId = null)
    {
        /** @var MyscrmContractApplicationService $service */
        $service = Yii::createObject(MyscrmContractApplicationService::className());
        $data = $service->getContractApplicationByContractId($contractId);

        /** @var ApplicationInfoMappingModel $model */
        $model = Yii::createObject(ApplicationInfoMappingModel::className());
        $data = $model->ensureAvailableApplicationList($data);

        $data = $this->appendUsedAuthorizationNumeric($orgCode, $data, $contractId, $excludeOrderId);

        return $data;
    }


    /**
     * 已用的应用授权数量 = 已出库 + 已授权
     * @param $data
     * @param $contractId
     * @param $excludeOrderId 排除单据ID
     * @return mixed
     */
    private function appendUsedAuthorizationNumeric($orgCode, $data, $contractId, $excludeOrderId)
    {
        /** @var ContractService $contractService */
        $contractService = Yii::createObject(ContractService::className());
        $contractCode = $contractService->getContractNum($contractId);


        /** @var MyscrmAuthorizeService $authService */
        $authService = Yii::createObject(MyscrmAuthorizeService::className());
       $authData = $authService->getContractAuthorizeCount($orgCode, $contractCode);

        foreach ($data as &$item) {
            //计算已出库的数量
            $total = (int)$this->orderRepository->getUsedAuthorizationNumericByContractApplicationId($item['contract_application_id'], $excludeOrderId);
            //计算已授权的数量
            foreach ($authData as $auth) {
                if ($item['authorize_application_id'] == $auth['ApplicationId'] &&
                    $item['is_qd_advanced'] == $auth['IsQdAdvanced']
                ) {
                    $total += $auth['total'];
                }
            }

            $item['used_authorization_numeric'] = $total ? $total : 0;
        }

        return $data;
    }

    /**
     * 获取所有商务应用列表
     * @return array|\yii\db\ActiveRecord[]
     */
    public function getApplicationList()
    {
        /** @var MyscrmApplicationInfoService $service */
        $service = Yii::createObject(MyscrmApplicationInfoService::className());
        $data = $service->getApplicationList();

        /** @var ApplicationInfoMappingModel $model */
        $model = Yii::createObject(ApplicationInfoMappingModel::className());
        $data = $model->ensureAvailableApplicationList($data);

        return $data;
    }

    /**
     * 通过应用ID查询需要授权的项目
     * @param $orgCode
     * @param $authorize_application_id
     * @param array $status 项目状态
     * @param $isOverdue
     * @return array|bool|\yii\db\ActiveRecord[]
     */
    public function getProjectList($orgCode, $authorize_application_id, $status, $isOverdue)
    {
        /** @var MyscrmApplicationService $appService */
        $appService = Yii::createObject(MyscrmApplicationService::className());
        $appCode = $appService->getAppCodeById($authorize_application_id);

        if (empty($appCode)) {
            return self::setAndReturn(__LINE__, '找不到应用：' . $authorize_application_id);
        }

        //如果续签的应用为新版微楼书，需要将旧版微楼的项目也显示出来
        if ($appCode == '5009') {
            $appCode = [5001, 5009];
        }

        /** @var MyscrmContractProjectService $contractProjectService */
        $contractProjectService = Yii::createObject(MyscrmContractProjectService::className());
        $data = $contractProjectService->getNeedAuthorizeProjectList($orgCode, $appCode, $status, $isOverdue);

        return array_values($data);
    }
}